
// <copyright file="WinApi.cs" company="Subhadra Software Solutions">
//   
// </copyright>
// <summary>
//   The win api.
// </summary>

namespace SubhadraSolutions.Sharp.Utils.Diagnostics
{
    using System;
    using System.Runtime.InteropServices;

    /// <summary>
    /// The win api.
    /// </summary>
    public static class WinApi
    {
        #region Constants

        /// <summary>
        /// The s c_ statu s_ proces s_ info.
        /// </summary>
        public const int SC_STATUS_PROCESS_INFO = 0;

        #endregion Constants

        #region Enums

        /// <summary>
        /// The sc m_ access.
        /// </summary>
        [Flags]
        public enum SCM_ACCESS : uint
        {
            /// <summary>
            ///     Required to connect to the service control manager.
            /// </summary>
            SC_MANAGER_CONNECT = 0x00001, 

            /// <summary>
            ///     Required to call the CreateService function to create a service
            ///     object and add it to the database.
            /// </summary>
            SC_MANAGER_CREATE_SERVICE = 0x00002, 

            /// <summary>
            ///     Required to call the EnumServicesStatusEx function to list the
            ///     services that are in the database.
            /// </summary>
            SC_MANAGER_ENUMERATE_SERVICE = 0x00004, 

            /// <summary>
            ///     Required to call the LockServiceDatabase function to acquire a
            ///     lock on the database.
            /// </summary>
            SC_MANAGER_LOCK = 0x00008, 

            /// <summary>
            ///     Required to call the QueryServiceLockStatus function to retrieve
            ///     the lock status information for the database.
            /// </summary>
            SC_MANAGER_QUERY_LOCK_STATUS = 0x00010, 

            /// <summary>
            ///     Required to call the NotifyBootConfigStatus function.
            /// </summary>
            SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020, 

            /// <summary>
            ///     Includes STANDARD_RIGHTS_REQUIRED, in addition to all access
            ///     rights in this table.
            /// </summary>
            SC_MANAGER_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED | SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_LOCK | SC_MANAGER_QUERY_LOCK_STATUS | SC_MANAGER_MODIFY_BOOT_CONFIG, 

            /// <summary>
            /// The generi c_ read.
            /// </summary>
            GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS, 

            /// <summary>
            /// The generi c_ write.
            /// </summary>
            GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG, 

            /// <summary>
            /// The generi c_ execute.
            /// </summary>
            GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK, 

            /// <summary>
            /// The generi c_ all.
            /// </summary>
            GENERIC_ALL = SC_MANAGER_ALL_ACCESS, 
        }

        /// <summary>
        /// The servic e_ accept.
        /// </summary>
        [Flags]
        public enum SERVICE_ACCEPT : uint
        {
            /// <summary>
            /// The stop.
            /// </summary>
            STOP = 0x00000001, 

            /// <summary>
            /// The paus e_ continue.
            /// </summary>
            PAUSE_CONTINUE = 0x00000002, 

            /// <summary>
            /// The shutdown.
            /// </summary>
            SHUTDOWN = 0x00000004, 

            /// <summary>
            /// The paramchange.
            /// </summary>
            PARAMCHANGE = 0x00000008, 

            /// <summary>
            /// The netbindchange.
            /// </summary>
            NETBINDCHANGE = 0x00000010, 

            /// <summary>
            /// The hardwareprofilechange.
            /// </summary>
            HARDWAREPROFILECHANGE = 0x00000020, 

            /// <summary>
            /// The powerevent.
            /// </summary>
            POWEREVENT = 0x00000040, 

            /// <summary>
            /// The sessionchange.
            /// </summary>
            SESSIONCHANGE = 0x00000080, 
        }

        /// <summary>
        /// The servic e_ access.
        /// </summary>
        [Flags]
        public enum SERVICE_ACCESS : uint
        {
            /// <summary>
            /// The standar d_ right s_ required.
            /// </summary>
            STANDARD_RIGHTS_REQUIRED = 0xF0000, 

            /// <summary>
            /// The servic e_ quer y_ config.
            /// </summary>
            SERVICE_QUERY_CONFIG = 0x00001, 

            /// <summary>
            /// The servic e_ chang e_ config.
            /// </summary>
            SERVICE_CHANGE_CONFIG = 0x00002, 

            /// <summary>
            /// The servic e_ quer y_ status.
            /// </summary>
            SERVICE_QUERY_STATUS = 0x00004, 

            /// <summary>
            /// The servic e_ enumerat e_ dependents.
            /// </summary>
            SERVICE_ENUMERATE_DEPENDENTS = 0x00008, 

            /// <summary>
            /// The servic e_ start.
            /// </summary>
            SERVICE_START = 0x00010, 

            /// <summary>
            /// The servic e_ stop.
            /// </summary>
            SERVICE_STOP = 0x00020, 

            /// <summary>
            /// The servic e_ paus e_ continue.
            /// </summary>
            SERVICE_PAUSE_CONTINUE = 0x00040, 

            /// <summary>
            /// The servic e_ interrogate.
            /// </summary>
            SERVICE_INTERROGATE = 0x00080, 

            /// <summary>
            /// The servic e_ use r_ define d_ control.
            /// </summary>
            SERVICE_USER_DEFINED_CONTROL = 0x00100, 

            /// <summary>
            /// The servic e_ al l_ access.
            /// </summary>
            SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL
        }

        /// <summary>
        /// The servic e_ control.
        /// </summary>
        [Flags]
        public enum SERVICE_CONTROL : uint
        {
            /// <summary>
            /// The stop.
            /// </summary>
            STOP = 0x00000001, 

            /// <summary>
            /// The pause.
            /// </summary>
            PAUSE = 0x00000002, 

            /// <summary>
            /// The continue.
            /// </summary>
            CONTINUE = 0x00000003, 

            /// <summary>
            /// The interrogate.
            /// </summary>
            INTERROGATE = 0x00000004, 

            /// <summary>
            /// The shutdown.
            /// </summary>
            SHUTDOWN = 0x00000005, 

            /// <summary>
            /// The paramchange.
            /// </summary>
            PARAMCHANGE = 0x00000006, 

            /// <summary>
            /// The netbindadd.
            /// </summary>
            NETBINDADD = 0x00000007, 

            /// <summary>
            /// The netbindremove.
            /// </summary>
            NETBINDREMOVE = 0x00000008, 

            /// <summary>
            /// The netbindenable.
            /// </summary>
            NETBINDENABLE = 0x00000009, 

            /// <summary>
            /// The netbinddisable.
            /// </summary>
            NETBINDDISABLE = 0x0000000A, 

            /// <summary>
            /// The deviceevent.
            /// </summary>
            DEVICEEVENT = 0x0000000B, 

            /// <summary>
            /// The hardwareprofilechange.
            /// </summary>
            HARDWAREPROFILECHANGE = 0x0000000C, 

            /// <summary>
            /// The powerevent.
            /// </summary>
            POWEREVENT = 0x0000000D, 

            /// <summary>
            /// The sessionchange.
            /// </summary>
            SESSIONCHANGE = 0x0000000E
        }

        /// <summary>
        /// The servic e_ state.
        /// </summary>
        public enum SERVICE_STATE : uint
        {
            /// <summary>
            /// The servic e_ stopped.
            /// </summary>
            SERVICE_STOPPED = 0x00000001, 

            /// <summary>
            /// The servic e_ star t_ pending.
            /// </summary>
            SERVICE_START_PENDING = 0x00000002, 

            /// <summary>
            /// The servic e_ sto p_ pending.
            /// </summary>
            SERVICE_STOP_PENDING = 0x00000003, 

            /// <summary>
            /// The servic e_ running.
            /// </summary>
            SERVICE_RUNNING = 0x00000004, 

            /// <summary>
            /// The servic e_ continu e_ pending.
            /// </summary>
            SERVICE_CONTINUE_PENDING = 0x00000005, 

            /// <summary>
            /// The servic e_ paus e_ pending.
            /// </summary>
            SERVICE_PAUSE_PENDING = 0x00000006, 

            /// <summary>
            /// The servic e_ paused.
            /// </summary>
            SERVICE_PAUSED = 0x00000007
        }

        /// <summary>
        /// The servic e_ types.
        /// </summary>
        [Flags]
        public enum SERVICE_TYPES
        {
            /// <summary>
            /// The servic e_ kerne l_ driver.
            /// </summary>
            SERVICE_KERNEL_DRIVER = 0x00000001, 

            /// <summary>
            /// The servic e_ fil e_ syste m_ driver.
            /// </summary>
            SERVICE_FILE_SYSTEM_DRIVER = 0x00000002, 

            /// <summary>
            /// The servic e_ wi n 32_ ow n_ process.
            /// </summary>
            SERVICE_WIN32_OWN_PROCESS = 0x00000010, 

            /// <summary>
            /// The servic e_ wi n 32_ shar e_ process.
            /// </summary>
            SERVICE_WIN32_SHARE_PROCESS = 0x00000020, 

            /// <summary>
            /// The servic e_ interactiv e_ process.
            /// </summary>
            SERVICE_INTERACTIVE_PROCESS = 0x00000100
        }

        /// <summary>
        /// The acces s_ mask.
        /// </summary>
        [Flags]
        private enum ACCESS_MASK : uint
        {
            /// <summary>
            /// The delete.
            /// </summary>
            DELETE = 0x00010000, 

            /// <summary>
            /// The rea d_ control.
            /// </summary>
            READ_CONTROL = 0x00020000, 

            /// <summary>
            /// The writ e_ dac.
            /// </summary>
            WRITE_DAC = 0x00040000, 

            /// <summary>
            /// The writ e_ owner.
            /// </summary>
            WRITE_OWNER = 0x00080000, 

            /// <summary>
            /// The synchronize.
            /// </summary>
            SYNCHRONIZE = 0x00100000, 

            /// <summary>
            /// The standar d_ right s_ required.
            /// </summary>
            STANDARD_RIGHTS_REQUIRED = 0x000f0000, 

            /// <summary>
            /// The standar d_ right s_ read.
            /// </summary>
            STANDARD_RIGHTS_READ = 0x00020000, 

            /// <summary>
            /// The standar d_ right s_ write.
            /// </summary>
            STANDARD_RIGHTS_WRITE = 0x00020000, 

            /// <summary>
            /// The standar d_ right s_ execute.
            /// </summary>
            STANDARD_RIGHTS_EXECUTE = 0x00020000, 

            /// <summary>
            /// The standar d_ right s_ all.
            /// </summary>
            STANDARD_RIGHTS_ALL = 0x001f0000, 

            /// <summary>
            /// The specifi c_ right s_ all.
            /// </summary>
            SPECIFIC_RIGHTS_ALL = 0x0000ffff, 

            /// <summary>
            /// The acces s_ syste m_ security.
            /// </summary>
            ACCESS_SYSTEM_SECURITY = 0x01000000, 

            /// <summary>
            /// The maximu m_ allowed.
            /// </summary>
            MAXIMUM_ALLOWED = 0x02000000, 

            /// <summary>
            /// The generi c_ read.
            /// </summary>
            GENERIC_READ = 0x80000000, 

            /// <summary>
            /// The generi c_ write.
            /// </summary>
            GENERIC_WRITE = 0x40000000, 

            /// <summary>
            /// The generi c_ execute.
            /// </summary>
            GENERIC_EXECUTE = 0x20000000, 

            /// <summary>
            /// The generi c_ all.
            /// </summary>
            GENERIC_ALL = 0x10000000, 

            /// <summary>
            /// The deskto p_ readobjects.
            /// </summary>
            DESKTOP_READOBJECTS = 0x00000001, 

            /// <summary>
            /// The deskto p_ createwindow.
            /// </summary>
            DESKTOP_CREATEWINDOW = 0x00000002, 

            /// <summary>
            /// The deskto p_ createmenu.
            /// </summary>
            DESKTOP_CREATEMENU = 0x00000004, 

            /// <summary>
            /// The deskto p_ hookcontrol.
            /// </summary>
            DESKTOP_HOOKCONTROL = 0x00000008, 

            /// <summary>
            /// The deskto p_ journalrecord.
            /// </summary>
            DESKTOP_JOURNALRECORD = 0x00000010, 

            /// <summary>
            /// The deskto p_ journalplayback.
            /// </summary>
            DESKTOP_JOURNALPLAYBACK = 0x00000020, 

            /// <summary>
            /// The deskto p_ enumerate.
            /// </summary>
            DESKTOP_ENUMERATE = 0x00000040, 

            /// <summary>
            /// The deskto p_ writeobjects.
            /// </summary>
            DESKTOP_WRITEOBJECTS = 0x00000080, 

            /// <summary>
            /// The deskto p_ switchdesktop.
            /// </summary>
            DESKTOP_SWITCHDESKTOP = 0x00000100, 

            /// <summary>
            /// The winst a_ enumdesktops.
            /// </summary>
            WINSTA_ENUMDESKTOPS = 0x00000001, 

            /// <summary>
            /// The winst a_ readattributes.
            /// </summary>
            WINSTA_READATTRIBUTES = 0x00000002, 

            /// <summary>
            /// The winst a_ accessclipboard.
            /// </summary>
            WINSTA_ACCESSCLIPBOARD = 0x00000004, 

            /// <summary>
            /// The winst a_ createdesktop.
            /// </summary>
            WINSTA_CREATEDESKTOP = 0x00000008, 

            /// <summary>
            /// The winst a_ writeattributes.
            /// </summary>
            WINSTA_WRITEATTRIBUTES = 0x00000010, 

            /// <summary>
            /// The winst a_ accessglobalatoms.
            /// </summary>
            WINSTA_ACCESSGLOBALATOMS = 0x00000020, 

            /// <summary>
            /// The winst a_ exitwindows.
            /// </summary>
            WINSTA_EXITWINDOWS = 0x00000040, 

            /// <summary>
            /// The winst a_ enumerate.
            /// </summary>
            WINSTA_ENUMERATE = 0x00000100, 

            /// <summary>
            /// The winst a_ readscreen.
            /// </summary>
            WINSTA_READSCREEN = 0x00000200, 

            /// <summary>
            /// The winst a_ al l_ access.
            /// </summary>
            WINSTA_ALL_ACCESS = 0x0000037f
        }

        #endregion Enums

        #region Public Methods and Operators

        /// <summary>
        /// The close service handle.
        /// </summary>
        /// <param name="hscObject">
        /// The hsc object.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool CloseServiceHandle(IntPtr hscObject)
        {
            return NativeMethods.CloseServiceHandle(hscObject);
        }

        /// <summary>
        /// The control service.
        /// </summary>
        /// <param name="hService">
        /// The h service.
        /// </param>
        /// <param name="dwControl">
        /// The dw control.
        /// </param>
        /// <param name="lpServiceStatus">
        /// The lp service status.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus)
        {
            return NativeMethods.ControlService(hService, dwControl, ref lpServiceStatus);
        }

        /// <summary>
        /// The open sc manager.
        /// </summary>
        /// <param name="machineName">
        /// The machine name.
        /// </param>
        /// <param name="databaseName">
        /// The database name.
        /// </param>
        /// <param name="dwAccess">
        /// The dw access.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        public static IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess)
        {
            return NativeMethods.OpenSCManager(machineName, databaseName, dwAccess);
        }

        /// <summary>
        /// The open service.
        /// </summary>
        /// <param name="hscManager">
        /// The hsc manager.
        /// </param>
        /// <param name="lpServiceName">
        /// The lp service name.
        /// </param>
        /// <param name="dwDesiredAccess">
        /// The dw desired access.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        public static IntPtr OpenService(IntPtr hscManager, string lpServiceName, uint dwDesiredAccess)
        {
            return NativeMethods.OpenService(hscManager, lpServiceName, dwDesiredAccess);
        }

        /// <summary>
        /// The query service status ex.
        /// </summary>
        /// <param name="serviceHandle">
        /// The service handle.
        /// </param>
        /// <param name="infoLevel">
        /// The info level.
        /// </param>
        /// <param name="buffer">
        /// The buffer.
        /// </param>
        /// <param name="bufferSize">
        /// The buffer size.
        /// </param>
        /// <param name="bytesNeeded">
        /// The bytes needed.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        public static bool QueryServiceStatusEx(IntPtr serviceHandle, int infoLevel, byte[] buffer, int bufferSize, out int bytesNeeded)
        {
            return NativeMethods.QueryServiceStatusEx(serviceHandle, infoLevel, buffer, bufferSize, out bytesNeeded);
        }

        #endregion Public Methods and Operators

        /// <summary>
        /// The servic e_ status.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        public struct SERVICE_STATUS
        {
            #region Fields

            /// <summary>
            /// The size of.
            /// </summary>
            public static readonly int SizeOf = Marshal.SizeOf(typeof(SERVICE_STATUS));

            /// <summary>
            /// The dw service type.
            /// </summary>
            public SERVICE_TYPES dwServiceType;

            /// <summary>
            /// The dw current state.
            /// </summary>
            public SERVICE_STATE dwCurrentState;

            /// <summary>
            /// The dw controls accepted.
            /// </summary>
            public uint dwControlsAccepted;

            /// <summary>
            /// The dw win 32 exit code.
            /// </summary>
            public uint dwWin32ExitCode;

            /// <summary>
            /// The dw service specific exit code.
            /// </summary>
            public uint dwServiceSpecificExitCode;

            /// <summary>
            /// The dw check point.
            /// </summary>
            public uint dwCheckPoint;

            /// <summary>
            /// The dw wait hint.
            /// </summary>
            public uint dwWaitHint;

            #endregion Fields
        }

        /// <summary>
        /// The native methods.
        /// </summary>
        private static class NativeMethods
        {
            #region Methods

            /// <summary>
            /// The close service handle.
            /// </summary>
            /// <param name="hscObject">
            /// The hsc object.
            /// </param>
            /// <returns>
            /// The <see cref="bool"/>.
            /// </returns>
            [DllImport("advapi32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool CloseServiceHandle(IntPtr hscObject);

            /// <summary>
            /// The control service.
            /// </summary>
            /// <param name="hService">
            /// The h service.
            /// </param>
            /// <param name="dwControl">
            /// The dw control.
            /// </param>
            /// <param name="lpServiceStatus">
            /// The lp service status.
            /// </param>
            /// <returns>
            /// The <see cref="bool"/>.
            /// </returns>
            [DllImport("advapi32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus);

            /// <summary>
            /// The open sc manager.
            /// </summary>
            /// <param name="machineName">
            /// The machine name.
            /// </param>
            /// <param name="databaseName">
            /// The database name.
            /// </param>
            /// <param name="dwAccess">
            /// The dw access.
            /// </param>
            /// <returns>
            /// The <see cref="IntPtr"/>.
            /// </returns>
            [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
            public static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);

            /// <summary>
            /// The open service.
            /// </summary>
            /// <param name="hscManager">
            /// The hsc manager.
            /// </param>
            /// <param name="lpServiceName">
            /// The lp service name.
            /// </param>
            /// <param name="dwDesiredAccess">
            /// The dw desired access.
            /// </param>
            /// <returns>
            /// The <see cref="IntPtr"/>.
            /// </returns>
            [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern IntPtr OpenService(IntPtr hscManager, string lpServiceName, uint dwDesiredAccess);

            /// <summary>
            /// The query service status ex.
            /// </summary>
            /// <param name="serviceHandle">
            /// The service handle.
            /// </param>
            /// <param name="infoLevel">
            /// The info level.
            /// </param>
            /// <param name="buffer">
            /// The buffer.
            /// </param>
            /// <param name="bufferSize">
            /// The buffer size.
            /// </param>
            /// <param name="bytesNeeded">
            /// The bytes needed.
            /// </param>
            /// <returns>
            /// The <see cref="bool"/>.
            /// </returns>
            [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
            public static extern bool QueryServiceStatusEx(IntPtr serviceHandle, int infoLevel, byte[] buffer, int bufferSize, out int bytesNeeded);

            #endregion Methods
        }

        /// <summary>
        /// The servic e_ statu s_ process.
        /// </summary>
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public class SERVICE_STATUS_PROCESS
        {
            /// <summary>
            /// The service type.
            /// </summary>
            public int serviceType;

            /// <summary>
            /// The current state.
            /// </summary>
            public int currentState;

            /// <summary>
            /// The controls accepted.
            /// </summary>
            public int controlsAccepted;

            /// <summary>
            /// The win 32 exit code.
            /// </summary>
            public int win32ExitCode;

            /// <summary>
            /// The service specific exit code.
            /// </summary>
            public int serviceSpecificExitCode;

            /// <summary>
            /// The check point.
            /// </summary>
            public int checkPoint;

            /// <summary>
            /// The wait hint.
            /// </summary>
            public int waitHint;

            /// <summary>
            /// The process id.
            /// </summary>
            public int processID;

            /// <summary>
            /// The service flags.
            /// </summary>
            public int serviceFlags;
        }
    }
}